/**************************************************************************************************
* Title: SmurfsPrimitiveFactor.cpp
* Authors: Gael Huber
* Description: Creates primitives 
**************************************************************************************************/
#include "SmurfsPrimitiveFactory.h"

/**************************************************************************************************
* Constructor
**************************************************************************************************/
PrimitiveFactory::PrimitiveFactory(void) {
	// Do nothing
}

/**************************************************************************************************
* Destructor
**************************************************************************************************/
PrimitiveFactory::~PrimitiveFactory(void) {
	// Do nothing
}

/**************************************************************************************************
* Returns a spherical mesh
*
* float radius	Radius of the sphere
* int segments		Number of segments into which the sphere will be split
**************************************************************************************************/
Mesh* PrimitiveFactory::createSphere(float radius, int segments) {
	// Define the standard segment radius
	float segmentRadius = PI / 2.0f / (segments + 1);
	int e = 0;

	// Number of separators for any given disc
	int numberOfSeparators = 4 * segments + 4;

	// Define and initialize an array of points
	std::vector<Vector3*> points;

	// Iterate through and define all points that compose the circle
	for(e = -segments; e <= segments; e++) {
		// Define the local radius of a particular disc
		float r = radius * cos(segmentRadius * e);
		float y = radius * sin(segmentRadius * e);

		// Create the local disc
		for(int seps = 0; seps < numberOfSeparators; seps++) {
			float z = r * sin(segmentRadius * seps) * -1.0f;
			float x = r * cos(segmentRadius * seps);
			points.push_back(new Vector3(x, y, z));
		}
	}

	// The points directly at the top and bottom of the sphere
	points.push_back(new Vector3(0, radius, 0));
	points.push_back(new Vector3(0, -radius, 0));

	// Index of each triangle
	std::vector<int> triangleIndices;

	// Create the triangles from the various indices
	for(e = 0; e < segments * 2; e++) {
		for(int i = 0; i < numberOfSeparators; i++) {
			triangleIndices.push_back(e * numberOfSeparators + i);
			triangleIndices.push_back(e * numberOfSeparators + i + numberOfSeparators);
			triangleIndices.push_back(e * numberOfSeparators + (i + 1) % numberOfSeparators + numberOfSeparators);

			triangleIndices.push_back(e * numberOfSeparators + (i + 1) % numberOfSeparators + numberOfSeparators);
			triangleIndices.push_back(e * numberOfSeparators + (i + 1) % numberOfSeparators);
			triangleIndices.push_back(e * numberOfSeparators + i);
		}
	}

	// Create triangles for "top" and "bottom" discs
	// top
	for(int i = 0; i < numberOfSeparators; i++) {
		triangleIndices.push_back(e * numberOfSeparators + i);
		triangleIndices.push_back(e * numberOfSeparators + (i + 1) % numberOfSeparators);
		triangleIndices.push_back(numberOfSeparators * (2 * segments + 1));
	}

	// bottom
	for(int i = 0; i < numberOfSeparators; i++) {
		triangleIndices.push_back(i);
		triangleIndices.push_back((i + 1) % numberOfSeparators);
		triangleIndices.push_back(numberOfSeparators * (2 * segments + 1) + 1);
	}

	// Define vertices and colors
	unsigned int numVerts = triangleIndices.size();
	float* vertices = new float[numVerts * 3];
	float* colors = new float[numVerts * 3];
	int currPoint = 0;

	for(unsigned int i = 0; i < numVerts; i++) {
		vertices[currPoint] = points[triangleIndices[i]]->x;
		colors[currPoint++] = (float)(i % 3) / 3.0f;
		vertices[currPoint] = points[triangleIndices[i]]->y;
		colors[currPoint++] = (float)((i+1) % 3) / 3.0f;
		vertices[currPoint] = points[triangleIndices[i]]->z;
		colors[currPoint++] = (float)((i+2) % 3) / 3.0f;
	}

	Mesh* mesh = new Mesh(S_TRIANGLES);
	mesh->createMesh(vertices, colors, numVerts * 3);
	return mesh;
}

/**************************************************************************************************
* Return a rectangle with specified dimensions.
**************************************************************************************************/
Mesh* PrimitiveFactory::createRectangle(float w, float h, float d) {
	float* vertices = new float[108];
	float* colors = new float[108];
	int vertexCount = 108;
	
	vertices[0] = -w; vertices[1] = h; vertices[2] = d;			// Bottom Left Of The Quad (Top)
	colors[0] = 0.0f; colors[1] = 0.0f; colors[2] = 1.0f;
	vertices[3] = -w; vertices[4] = h; vertices[5] = -d;	// Top Left Of The Quad (Top)
	colors[3] = 0.0f; colors[4] = 1.0f; colors[5] = 0.0f;
	vertices[6] = w; vertices[7] = h; vertices[8] = -d;		// Top Right Of The Quad (Top)
	colors[6] = 1.0f; colors[7] = 0.0f; colors[8] = 0.0f;

	vertices[9] = w; vertices[10] = h; vertices[11] = -d;		// Top Right Of The Quad (Top)
	colors[9] = 1.0f; colors[10] = 0.0f; colors[11] = 0.0f;		
	vertices[12] = w; vertices[13] = h; vertices[14] = d;			// Bottom Right Of The Quad (Top)
	colors[12] = 0.0f; colors[13] = 1.0f; colors[14] = 1.0f;
	vertices[15] = -w; vertices[16] = h; vertices[17] = d;			// Bottom Left Of The Quad (Top)
	colors[15] = 0.0f; colors[16] = 0.0f; colors[17] = 1.0f;

	vertices[18] = -w; vertices[19] = -h; vertices[20] = -d;			// Bottom Left Of The Quad (Bottom)
	colors[18] = 0.0f; colors[19] = 0.0f; colors[20] = 1.0f;
	vertices[21] = -w; vertices[22] = -h; vertices[23] = d;			// Top Left Of The Quad (Bottom)
	colors[21] = 0.0f; colors[22] = 1.0f; colors[23] = 0.0f;
	vertices[24] = w; vertices[25] = -h; vertices[26] = d;			// Top Right Of The Quad (Bottom)
	colors[24] = 1.0f; colors[25] = 0.0f; colors[26] = 0.0f;

	vertices[27] = w; vertices[28] = -h; vertices[29] = d;			// Top Right Of The Quad (Bottom)
	colors[27] = 1.0f; colors[28] = 0.0f; colors[29] = 0.0f;
	vertices[30] = w; vertices[31] = -h; vertices[32] = -d;			// Bottom Right Of The Quad (Bottom)
	colors[30] = 0.0f; colors[31] = 1.0f; colors[32] = 1.0f;
	vertices[33] = -w; vertices[34] = -h; vertices[35] = -d;			// Bottom Left Of The Quad (Bottom)
	colors[33] = 0.0f; colors[34] = 0.0f; colors[35] = 1.0f;

	vertices[36] = -w; vertices[37] = -h; vertices[38] = d;			// Bottom Left Of The Quad (Front)
	colors[36] = 0.0f; colors[37] = 0.0f; colors[38] = 1.0f;
	vertices[39] = -w; vertices[40] = h; vertices[41] = d;			// Top Left Of The Quad (Front)
	colors[39] = 0.0f; colors[40] = 1.0f; colors[41] = 0.0f;
	vertices[42] = w; vertices[43] = h; vertices[44] = d;			// Top Right Of The Quad (Front)
	colors[42] = 1.0f; colors[43] = 0.0f; colors[44] = 0.0f;

	vertices[45] = w; vertices[46] = h; vertices[47] = d;			// Top Right Of The Quad (Front)
	colors[45] = 1.0f; colors[46] = 0.0f; colors[47] = 0.0f;
	vertices[48] = w; vertices[49] = -h; vertices[50] = d;			// Bottom Right Of The Quad (Front)
	colors[48] = 0.0f; colors[49] = 1.0f; colors[50] = 1.0f;
	vertices[51] = -w; vertices[52] = -h; vertices[53] = d;			// Bottom Left Of The Quad (Front)
	colors[51] = 0.0f; colors[52] = 0.0f; colors[53] = 1.0f;

	vertices[54] = w; vertices[55] = -h; vertices[56] = -d;			// Bottom Left Of The Quad (Back)
	colors[54] = 1.0f; colors[55] = 0.0f; colors[56] = 0.0f;
	vertices[57] = w; vertices[58] = h; vertices[59] = -d;			// Top Left Of The Quad (Back)
	colors[57] = 0.0f; colors[58] = 1.0f; colors[59] = 1.0f;
	vertices[60] = -w; vertices[61] = h; vertices[62] = -d;			// Top Right Of The Quad (Back)
	colors[60] = 0.0f; colors[61] = 0.0f; colors[62] = 1.0f;

	vertices[63] = -w; vertices[64] = h; vertices[65] = -d;			// Top Right Of The Quad (Back)
	colors[63] = 0.0f; colors[64] = 0.0f; colors[65] = 1.0f;
	vertices[66] = -w; vertices[67] = -h; vertices[68] = -d;			// Bottom Right Of The Quad (Back)
	colors[66] = 0.0f; colors[67] = 1.0f; colors[68] = 0.0f;
	vertices[69] = w; vertices[70] = -h; vertices[71] = -d;			// Bottom Left Of The Quad (Back)
	colors[69] = 1.0f; colors[70] = 0.0f; colors[71] = 0.0f;

	vertices[72] = -w; vertices[73] = -h; vertices[74] = -d;			// Bottom Left Of The Quad (Left)
	colors[72] = 0.0f; colors[73] = 0.0f; colors[74] = 1.0f;
	vertices[75] = -w; vertices[76] = h; vertices[77] = d;			// Top Right Of The Quad (Left)
	colors[75] = 1.0f; colors[76] = 0.0f; colors[77] = 0.0f;
	vertices[78] = -w; vertices[79] = h; vertices[80] = d;			// Top Right Of The Quad (Left)
	colors[78] = 1.0f; colors[79] = 0.0f; colors[80] = 0.0f;

	vertices[81] = -w; vertices[82] = h; vertices[83] = d;			// Top Right Of The Quad (Left)
	colors[81] = 1.0f; colors[82] = 0.0f; colors[83] = 0.0f;
	vertices[84] = -w; vertices[85] = -h; vertices[86] = d;			// Bottom Right Of The Quad (Left)
	colors[84] = 0.0f; colors[85] = 1.0f; colors[86] = 1.0f;
	vertices[87] = -w; vertices[88] = -h; vertices[89] = -d;			// Bottom Left Of The Quad (Left)
	colors[87] = 0.0f; colors[88] = 0.0f; colors[89] = 1.0f;

	vertices[90] = w; vertices[91] = -h; vertices[92] = d;			// Bottom Left Of The Quad (Right)
	colors[90] = 0.0f; colors[91] = 0.0f; colors[92] = 1.0f;
	vertices[93] = w; vertices[94] = h; vertices[95] = d;			// Top Left Of The Quad (Right)
	colors[93] = 0.0f; colors[94] = 1.0f; colors[95] = 0.0f;
	vertices[96] = w; vertices[97] = h; vertices[98] = -d;			// Top Right Of The Quad (Right)
	colors[96] = 1.0f; colors[97] = 0.0f; colors[98] = 0.0f;

	vertices[99] = w; vertices[100] = h; vertices[101] = -d;			// Top Right Of The Quad (Right)
	colors[99] = 1.0f; colors[100] = 0.0f; colors[101] = 0.0f;
	vertices[102] = w; vertices[103] = -h; vertices[104] = -d;			// Bottom Right Of The Quad (Right)
	colors[102] = 0.0f; colors[103] = 1.0f; colors[104] = 1.0f;
	vertices[105] = w; vertices[106] = -h; vertices[107] = d;			// Bottom Left Of The Quad (Right)
	colors[105] = 0.0f; colors[106] = 0.0f; colors[107] = 1.0f;

	Mesh* mesh = new Mesh(S_TRIANGLES);
	mesh->createMesh(vertices, colors, vertexCount);
	return mesh;
}